#pragma once

#include<iostream>
#include<pthread.h>
#include<unistd.h> 
#include<queue>
#include<mutex>

// #define INIT_MTX(mtx) phread_mutex_init(&mtx,nullptr)
// #define INIT_COND(cond) phread_cond_init()
const int gDefaultCap=5;

template<class T>
class BlockQueue
{
private:
    inline bool isQueueEmpty()
    {
        return _bq.empty();
    }
    inline bool isQueueFull()
    {
        return _bq.size()==gDefaultCap;
    }
public:
    BlockQueue(int capacity=gDefaultCap):_capacity(capacity)
    {
        pthread_mutex_init(&_mtx,nullptr);
        pthread_cond_init(&_Empty,nullptr);
        pthread_cond_init(&_Full,nullptr);
    }
    void push(const T& in)//生产
    {
        //加锁解锁
        pthread_mutex_lock(&_mtx);
        //先对临界资源检测，再访问临界资源
        while(isQueueFull())//生产者while等待 当满的时候等待，等待结束的时候再判断一次再处理后面的任务
        {

            //pthread_cond_wait的第二个参数是一个锁，如果等待成功，自动释放传入的锁。否则挂起的时候还会持有锁
            //唤醒成功时函数返回自动获取锁，继续执行wait之后的代码
            //wait函数可能等待失败，要处理伪等待的情况
            pthread_cond_wait(&_Full,&_mtx);

        }
        //开始访问临界资源
        _bq.push(in);
        if(_bq.size()>=_capacity/2)  
        {
          pthread_cond_signal(&_Empty);
        }  
        pthread_mutex_unlock(&_mtx);
    }
    void pop(T* out)
    {
        pthread_mutex_lock(&_mtx);
        while(isQueueEmpty()) 
        {
            pthread_cond_wait(&_Empty,&_mtx);
        }
        *out=_bq.front();
        _bq.pop();
        pthread_mutex_unlock(&_mtx);
        //在unlock之前之后都可以唤醒
        pthread_cond_signal(&_Full);//如果另一方没有在等待自动丢弃唤醒信号
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mtx);
        pthread_cond_destroy(&_Full);
        pthread_cond_destroy(&_Empty);
    }
private:
    std::queue<T> _bq;//阻塞队列
    int _capacity; //容量上限
    pthread_mutex_t _mtx; //互斥锁表示队列安全
    pthread_cond_t _Empty; //用它来表示阻塞队列是否为空的条件
    pthread_cond_t _Full;//生产者关心：是否满了
};